	package storm.Processors;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Vector;

import storm.Tasks.Task;

/***********************************************/
public class LEATCache_1 extends Cache {
	Vector <storm.Tasks.Task>Tasks;
	String nameCP ;
	Memory memory;
	private PrintWriter outPutCartofile;
	private PrintWriter outPutLogFile;
	
	public LEATCache_1 (){
		super();
		this.Tasks = new Vector<Task>();
		 nameCP = this.toString()+"_CP";
		
			
			 
	
			 
		 //this.memory = new Memory();
	}
	public void setMemory(int s){
		 try {
			 if (this.getOwnFieldStringValue("cartofile" ) != null){
				 
			outPutCartofile =  new PrintWriter(new BufferedWriter
					   (new FileWriter(this.getOwnFieldStringValue("cartofile" ))));
			 }
			 if (this.getOwnFieldStringValue("logfile" ) != null){
				  outPutLogFile = new PrintWriter(new BufferedWriter
						   (new FileWriter(this.getOwnFieldStringValue("logfile" ))));
				 
			 }
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.memory = new Memory(s);
	}

	
int getpen(Task T){
		double res =0;
		double used =0;
		int Xi= T.getOwnFieldIntValue(this.nameCP+"Xi");
		int Xiref = T.getOwnFieldIntValue("Xi");
		int Li = T.getOwnFieldIntValue("Li");
		double consommer =Double.valueOf( T.getOwnFieldStringValue(this.nameCP));
		double Tpen = Double.parseDouble(this.getOwnFieldStringValue("BurstModeAccesTime"));
		double resOld =Double.parseDouble( T.getOwnFieldStringValue(this.nameCP+"predMAJ"));
		//J'ajoute consommer pour lisser le graphe et ne pas avoir d'escalier
		res =  (Xi/(1.0-Math.exp(-Li*(T.getWCET()+consommer)/1000.0*this.Kernel.getprecision())  ))*(1.0-Math.exp(-Li*((T.getEET()+consommer))/1000.0*this.Kernel.getprecision())); ;
		// Mise ? jour des dates du caches d?ja utilis? dans le cas o? on se reexecute 
		int cacheUsed = T.getOwnFieldIntValue(this.nameCP+"predXi");
		double needed = 0;
		double ToMaj=0;
		if (Xi != Xiref){
			if (T.getEET() > 0) {
			double resRef =  (Xiref/(1.0-Math.exp(-Li*(T.getWCET()+consommer)/1000.0*this.Kernel.getprecision())  ))*(1.0-Math.exp(-Li*((T.getEET()+consommer))/1000.0*this.Kernel.getprecision()));
			double resRefOld =  (Xiref/(1.0-Math.exp(-Li*(T.getWCET()+consommer)/1000.0*this.Kernel.getprecision())  ))*(1.0-Math.exp(-Li*((T.getEET()+consommer-1))/1000.0*this.Kernel.getprecision()));
			ToMaj=Math.round(((resRef - resRefOld)   -(res - resOld) ) * 1.1);
			
			T.setOwnFieldIntValue(this.nameCP+"predMAJ",(int) res);
			//this.memory.maj(T,(int)(resRef -res),this.Kernel.getTime());
			this.memory.maj(T,(int)(ToMaj),this.Kernel.getTime());
			
			 needed = (res-cacheUsed);
			} 
		/* 
		 *  Un certain nombre de ligne de cache dont on a besoin ne sont pas pr?sente
		 */
		this.memory.addLine(T, (int) (res-cacheUsed), this.Kernel.getTime());
		T.setOwnFieldIntValue(this.nameCP+"predXi",(int) res);
		if (T.getId() == 1) System.out.println(this.Kernel.getTime() + "  " + (res-cacheUsed) + "  " + ToMaj);;
		}
		else { // premi?re ex?cution
		   needed = res - this.memory.getUsed(T);
			this.memory.addLine(T, (int) needed, this.Kernel.getTime());
			if (T.getId() == 1) System.out.println(this.Kernel.getTime() + "  " + (needed) + "  " + 0);
		}
		/**
		 *  Penalit?s temporelle
		 */
		String r = T.getOwnFieldStringValue("RWratio");
		double rw_ratio = Double.valueOf(r);
		double neededTime = needed *(1+ rw_ratio);
		neededTime = Tpen * res; 
		int facturer = 0;
		if ( (neededTime-consommer) > 1){
			facturer = 1;
			T.setOwnFieldStringValue(this.nameCP, (consommer+1  ) +"");
		}
	//System.out.println(this.Kernel.getTime()  + " -- " + this.memory.getCarto());
		if(outPutCartofile!=null) {
			outPutCartofile.println(this.Kernel.getTime()  + " -- " + this.memory.getCarto());
			outPutCartofile.flush();
		}
		if(outPutLogFile!=null) {

			outPutLogFile.println(T.getId() +  "   "+ this.Kernel.getTime()  + "  "+ res + "  " + Xi + "  " + this.memory.getUsed(T) + "  " +  T.getOwnFieldStringValue(this.nameCP) + "  "  +  T.getOwnFieldIntValue(this.nameCP+"predXi"));
			outPutLogFile.flush();
		}
	//  if (T.getId() ==1)
//		System.out.println(this.Kernel.getTime()  + "  " +  res + "  " + Xi + "  " + this.memory.getUsed(T) + "  " +  T.getOwnFieldStringValue(this.nameCP));
	//	System.out.println(this.Kernel.getTime()  + "  " +  this.memory.getCarto());
		return facturer ;
}
	public int havePenality(Task T) {
		// TODO Auto-generated method stub
		//System.out.println(");
		if (this.Tasks.contains(T)){
			
			
			if (T.getET()==0) {
				int Xi = T.getOwnFieldIntValue("Xi");
				int UsedCached = this.memory.getUsed(T) ;
				int info =0;
				if (UsedCached< Xi) {
					info =  Xi- UsedCached;
					if (info == 1 ) info =0;
				}
				else { 
					info = Xi;
				}
				T.setOwnFieldIntValue(this.nameCP, 0);
				T.setOwnFieldIntValue(this.nameCP+"Xi", info );
				T.setOwnFieldIntValue(this.nameCP+"predXi", 0);
				T.setOwnFieldIntValue(this.nameCP+"predMAJ",0);
			}
			//int compteur = T.getOwnFieldIntValue(this.nameCP);
			/**
			 * Cold misses 
			 */
			int value = this.getpen( T);
			if (value > 0 )return value;
		
			
		}
		else {
			this.Tasks.add(T);
			T.setOwnFieldIntValue(this.nameCP,0);
			T.setOwnFieldIntValue(this.nameCP+"predXi", 0);
			T.setOwnFieldIntValue(this.nameCP+"Xi", T.getOwnFieldIntValue("Xi") );
			T.setOwnFieldIntValue(this.nameCP+"predMAJ",0);
			
			
		}
		
		return 0;
	}

	
}
